{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- https://course.rs/basic/formatted-output.html\n",
    "- https://practice-zh.course.rs/formatted-output.html"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**TL;DR**\n",
    "\n",
    "- Rust 格式化输出主要靠 `print!`/`println!`/`format!`（标准输出或生成 `String`）以及 `eprint!`/`eprintln!`（标准错误）。\n",
    "- `{}` 依赖 `Display`，`{:?}`/`{:#?}` 依赖 `Debug`；结构体可 `#[derive(Debug)]` 或手动实现 `Display`，外部类型可用 newtype 包装再实现。\n",
    "- 支持位置/具名参数、宽度、对齐、填充、精度、小数截断、进制（`#b/#o/#x` 等）、科学计数（`e/E`）、指针（`p`）以及 `{` `}` 转义。\n",
    "- 1.58 起可直接在格式化字符串中捕获在作用域内的变量：`println!(\"Hello, {person}!\");` 同时变量也能用于宽度、精度等参数。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Hello\n",
      "Hello, world!\n",
      "The number is 1\n",
      "(3, 4)\n",
      "4\n",
      "1 2\n",
      "0042\n"
     ]
    }
   ],
   "source": [
    "println!(\"Hello\");                 // => \"Hello\"\n",
    "println!(\"Hello, {}!\", \"world\");   // => \"Hello, world!\"\n",
    "println!(\"The number is {}\", 1);   // => \"The number is 1\"\n",
    "println!(\"{:?}\", (3, 4));          // => \"(3, 4)\"\n",
    "println!(\"{value}\", value=4);      // => \"4\"\n",
    "println!(\"{} {}\", 1, 2);           // => \"1 2\"\n",
    "println!(\"{:04}\", 42);             // => \"0042\" with leading zeros"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# print!，println!，format!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "hello, world\n",
      "hello, world!\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "{\n",
    "    let s = \"hello\";\n",
    "    println!(\"{}, world\", s);\n",
    "    let s1 = format!(\"{}, world\", s); // 将格式化文本输出到 String 字符串\n",
    "    print!(\"{}\", s1);\n",
    "    print!(\"{}\\n\", \"!\");\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## eprint!，eprintln!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Error: Could not complete task\n"
     ]
    }
   ],
   "source": [
    "eprintln!(\"Error: Could not complete task\");"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# {} 与 {:?}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "当你在写代码需要调试时，使用 `{:?}`，剩下的场景，选择 `{}`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Debug 特征"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "3.1415926, \"hello\", [1, 2, 3], Person { name: \"sunface\", age: 18 }\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#[derive(Debug)]\n",
    "struct Person {\n",
    "    name: String,\n",
    "    age: u8\n",
    "}\n",
    "\n",
    "{\n",
    "    let i = 3.1415926;\n",
    "    let s = String::from(\"hello\");\n",
    "    let v = vec![1, 2, 3];\n",
    "    let p = Person{name: \"sunface\".to_string(), age: 18};\n",
    "    println!(\"{:?}, {:?}, {:?}, {:?}\", i, s, v, p);\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "对于数值、字符串、数组，可以直接使用 `{:?}` 进行输出，但是对于结构体，需要[派生`Debug`](https://course.rs/appendix/derive.html)特征后，才能进行输出，总之很简单。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Display 特征"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "ename": "Error",
     "evalue": "`Vec<{integer}>` doesn't implement `std::fmt::Display`",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[E0277] Error:\u001b[0m `Vec<{integer}>` doesn't implement `std::fmt::Display`",
      "   \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_6:1:1 \u001b[38;5;246m]\u001b[0m",
      "   \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m8 │\u001b[0m \u001b[38;5;249mp\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249m!\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249m\"\u001b[0m\u001b[38;5;249m{\u001b[0m\u001b[38;5;249m}\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m{\u001b[0m\u001b[38;5;249m}\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;100m{\u001b[0m\u001b[38;5;100m}\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m{\u001b[0m\u001b[38;5;249m}\u001b[0m\u001b[38;5;249m\"\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;54mv\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mp\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m                   \u001b[38;5;100m─\u001b[0m\u001b[38;5;100m┬\u001b[0m             \u001b[38;5;54m┬\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m                    \u001b[38;5;100m╰\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m required by this formatting parameter",
      " \u001b[38;5;240m  │\u001b[0m                                  \u001b[38;5;54m│\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m                                  \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m `Vec<{integer}>` cannot be formatted with the default formatter",
      "\u001b[38;5;246m───╯\u001b[0m"
     ]
    },
    {
     "ename": "Error",
     "evalue": "`Person` doesn't implement `std::fmt::Display`",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[E0277] Error:\u001b[0m `Person` doesn't implement `std::fmt::Display`",
      "   \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_6:1:1 \u001b[38;5;246m]\u001b[0m",
      "   \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m8 │\u001b[0m \u001b[38;5;249mp\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249m!\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249m\"\u001b[0m\u001b[38;5;249m{\u001b[0m\u001b[38;5;249m}\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m{\u001b[0m\u001b[38;5;249m}\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m{\u001b[0m\u001b[38;5;249m}\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;100m{\u001b[0m\u001b[38;5;100m}\u001b[0m\u001b[38;5;249m\"\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mv\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;54mp\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m                       \u001b[38;5;100m─\u001b[0m\u001b[38;5;100m┬\u001b[0m            \u001b[38;5;54m┬\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m                        \u001b[38;5;100m╰\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m required by this formatting parameter",
      " \u001b[38;5;240m  │\u001b[0m                                     \u001b[38;5;54m│\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m                                     \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m `Person` cannot be formatted with the default formatter",
      "\u001b[38;5;246m───╯\u001b[0m"
     ]
    }
   ],
   "source": [
    "let i = 3.1415926;\n",
    "let s = String::from(\"hello\");\n",
    "let v = vec![1, 2, 3];\n",
    "let p = Person {\n",
    "    name: \"sunface\".to_string(),\n",
    "    age: 18,\n",
    "};\n",
    "println!(\"{}, {}, {}, {}\", i, s, v, p);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "运行后可以看到 `v` 和 `p` 都无法通过编译，因为没有实现 `Display` 特征，但是你又不能像派生 `Debug` 一般派生 `Display`，只能另寻他法：\n",
    "\n",
    "- 使用 `{:?}` 或 `{:#?}`\n",
    "- 为自定义类型实现 `Display` 特征\n",
    "- 使用 `newtype` 为外部类型实现 `Display` 特征"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### {:#?}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`{:#?}` 与 `{:?}` 几乎一样，唯一的区别在于它能更优美地输出内容：\n",
    "\n",
    "因此对于 `Display` 不支持的类型，可以考虑使用 `{:#?}` 进行格式化，虽然理论上它更适合进行调试输出。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "3.1415926, \"hello\", [\n",
      "    1,\n",
      "    2,\n",
      "    3,\n",
      "], Person {\n",
      "    name: \"sunface\",\n",
      "    age: 18,\n",
      "}\n"
     ]
    }
   ],
   "source": [
    "let i = 3.1415926;\n",
    "let s = String::from(\"hello\");\n",
    "let v = vec![1, 2, 3];\n",
    "let p = Person {\n",
    "    name: \"sunface\".to_string(),\n",
    "    age: 18,\n",
    "};\n",
    "println!(\"{:#?}, {:#?}, {:#?}, {:#?}\", i, s, v, p);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 为自定义类型实现 Display 特征"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "大佬在上，请受我一拜，小弟姓名sunface，年芳18，家里无田又无车，生活苦哈哈\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "struct Person {\n",
    "    name: String,\n",
    "    age: u8,\n",
    "}\n",
    "\n",
    "use std::fmt;\n",
    "impl fmt::Display for Person {\n",
    "    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n",
    "        write!(\n",
    "            f,\n",
    "            \"大佬在上，请受我一拜，小弟姓名{}，年芳{}，家里无田又无车，生活苦哈哈\",\n",
    "            self.name, self.age\n",
    "        )\n",
    "    }\n",
    "}\n",
    "\n",
    "{\n",
    "    let p = Person {\n",
    "        name: \"sunface\".to_string(),\n",
    "        age: 18,\n",
    "    };\n",
    "    println!(\"{}\", p);\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 为外部类型实现 Display 特征"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "数组是：[1, 2, 3]\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "struct Array(Vec<i32>);\n",
    "\n",
    "use std::fmt;\n",
    "impl fmt::Display for Array { // Array 就是我们的 newtype，它将想要格式化输出的 Vec 包裹在内，最后只要为 Array 实现 Display 特征，即可进行格式化输出：\n",
    "    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n",
    "        write!(f, \"数组是：{:?}\", self.0)\n",
    "    }\n",
    "}\n",
    "\n",
    "{\n",
    "    let arr = Array(vec![1, 2, 3]);\n",
    "    println!(\"{}\", arr);\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "> AI:\n",
    "\n",
    "“外部类型”（外部类型/外部特征）指的是**既不是在当前 crate 中定义的类型，也不是当前 crate 定义的特征**。\n",
    "\n",
    "Rust 有所谓的“孤儿规则（orphan rule）”：只有当你控制其中至少一方（类型或特征）时，才允许为这对组合提供实现（impl）。具体来说：\n",
    "\n",
    "- **内部类型**：在当前 crate（模块）里定义的类型，例如 `struct MyType { ... }`。\n",
    "- **外部类型**：在别的 crate（包含标准库）里定义的类型，例如标准库的 `Vec<T>`、`String`，或第三方库提供的结构体。\n",
    "\n",
    "同理：\n",
    "\n",
    "- **内部特征**：在当前 crate 中定义的 trait。\n",
    "- **外部特征**：标准库或其他 crate 定义的 trait，例如 `std::fmt::Display`。\n",
    "\n",
    "因为 `Vec<T>`（类型）和 `Display`（特征）都不是你当前 crate 定义的，想直接写 `impl Display for Vec<i32>` 会触发孤儿规则而被禁止。解决办法就是使用 **newtype**：自己在当前 crate 新建一个包裹类型（如 `struct Array(Vec<i32>);`），这样 `Array` 就成了内部类型，你就有权利为它实现外部特征 `Display` 了。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 位置参数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "12\n",
      "21\n",
      "Alice, this is Bob. Bob, this is Alice\n",
      "2112\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "{\n",
    "    println!(\"{}{}\", 1, 2); // =>\"12\"\n",
    "    println!(\"{1}{0}\", 1, 2); // =>\"21\"\n",
    "    // => Alice, this is Bob. Bob, this is Alice\n",
    "    println!(\"{0}, this is {1}. {1}, this is {0}\", \"Alice\", \"Bob\");\n",
    "    println!(\"{1}{}{0}{}\", 1, 2); // => 2112\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 具名参数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "test\n",
      "2 1\n",
      "a 3 b\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "{\n",
    "    println!(\"{argument}\", argument = \"test\"); // => \"test\"\n",
    "    println!(\"{name} {}\", 1, name = 2); // => \"2 1\"\n",
    "    println!(\"{a} {c} {b}\", a = \"a\", b = 'b', c = 3); // => \"a 3 b\"\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "ename": "Error",
     "evalue": "positional arguments cannot follow named arguments",
     "output_type": "error",
     "traceback": [
      "println!(\"{abc} {1}\", abc = \"def\", 2); // 带名称的参数必须放在不带名称参数的后面",
      "\u001b[91m                                   ^\u001b[0m \u001b[94mpositional arguments must be before named arguments\u001b[0m",
      "println!(\"{abc} {1}\", abc = \"def\", 2); // 带名称的参数必须放在不带名称参数的后面",
      "\u001b[91m                      ^^^^^^^^^^^\u001b[0m \u001b[94mnamed argument\u001b[0m",
      "positional arguments cannot follow named arguments"
     ]
    }
   ],
   "source": [
    "println!(\"{abc} {1}\", abc = \"def\", 2); // 带名称的参数必须放在不带名称参数的后面"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 格式化参数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "3.14\n",
      "3.14\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "{\n",
    "    let v = 3.1415926;\n",
    "    // Display => 3.14\n",
    "    println!(\"{:.2}\", v);\n",
    "    // Debug => 3.14\n",
    "    println!(\"{:.2?}\", v);\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## [宽度](https://course.rs/basic/formatted-output.html#宽度)\n",
    "\n",
    "宽度用来指示输出目标的长度，如果长度不够，则进行填充和对齐："
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## [字符串填充](https://course.rs/basic/formatted-output.html#字符串填充)\n",
    "\n",
    "字符串格式化默认使用空格进行填充，并且进行左对齐。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Hello x    !\n",
      "Hello x    !\n",
      "Hello x    !\n",
      "Hello x    !\n",
      "Hello x    !5\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "{\n",
    "    //-----------------------------------\n",
    "    // 以下全部输出 \"Hello x    !\"\n",
    "    // 为\"x\"后面填充空格，补齐宽度5\n",
    "    println!(\"Hello {:5}!\", \"x\");\n",
    "    // 使用参数5来指定宽度\n",
    "    println!(\"Hello {:1$}!\", \"x\", 5);\n",
    "    // 使用x作为占位符输出内容，同时使用5作为宽度\n",
    "    println!(\"Hello {1:0$}!\", 5, \"x\");\n",
    "    // 使用有名称的参数作为宽度\n",
    "    println!(\"Hello {:width$}!\", \"x\", width = 5);\n",
    "    //-----------------------------------\n",
    "\n",
    "    // 使用参数5为参数x指定宽度，同时在结尾输出参数5 => Hello x    !5\n",
    "    println!(\"Hello {:1$}!{}\", \"x\", 5);\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### [数字填充:符号和 0](https://course.rs/basic/formatted-output.html#数字填充符号和-0)\n",
    "\n",
    "数字格式化默认也是使用空格进行填充，但与字符串左对齐不同的是，数字是右对齐。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Hello     5!\n",
      "Hello +5!\n",
      "Hello 00005!\n",
      "Hello -0005!\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "{\n",
    "    // 宽度是5 => Hello     5!\n",
    "    println!(\"Hello {:5}!\", 5);\n",
    "    // 显式的输出正号 => Hello +5!\n",
    "    println!(\"Hello {:+}!\", 5);\n",
    "    // 宽度5，使用0进行填充 => Hello 00005!\n",
    "    println!(\"Hello {:05}!\", 5);\n",
    "    // 负号也要占用一位宽度 => Hello -0005!\n",
    "    println!(\"Hello {:05}!\", -5);\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## [对齐](https://course.rs/basic/formatted-output.html#对齐)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Hello x    !\n",
      "Hello     x!\n",
      "Hello   x  !\n",
      "Hello x&&&&!\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "{\n",
    "    // 以下全部都会补齐5个字符的长度\n",
    "    // 左对齐 => Hello x    !\n",
    "    println!(\"Hello {:<5}!\", \"x\");\n",
    "    // 右对齐 => Hello     x!\n",
    "    println!(\"Hello {:>5}!\", \"x\");\n",
    "    // 居中对齐 => Hello   x  !\n",
    "    println!(\"Hello {:^5}!\", \"x\");\n",
    "\n",
    "    // 对齐并使用指定符号填充 => Hello x&&&&!\n",
    "    // 指定符号填充的前提条件是必须有对齐字符\n",
    "    println!(\"Hello {:&<5}!\", \"x\");\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## [精度](https://course.rs/basic/formatted-output.html#精度)\n",
    "\n",
    "精度可以用于控制浮点数的精度或者字符串的长度"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "3.14\n",
      "+3.14\n",
      "3\n",
      "3.1416\n",
      "hi我\n",
      "Hello abc!\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "{\n",
    "    let v = 3.1415926;\n",
    "    // 保留小数点后两位 => 3.14\n",
    "    println!(\"{:.2}\", v);\n",
    "    // 带符号保留小数点后两位 => +3.14\n",
    "    println!(\"{:+.2}\", v);\n",
    "    // 不带小数 => 3\n",
    "    println!(\"{:.0}\", v);\n",
    "    // 通过参数来设定精度 => 3.1416，相当于{:.4}\n",
    "    println!(\"{:.1$}\", v, 4);\n",
    "\n",
    "    let s = \"hi我是Sunface孙飞\";\n",
    "    // 保留字符串前三个字符 => hi我\n",
    "    println!(\"{:.3}\", s);\n",
    "    // {:.*}接收两个参数，第一个是精度，第二个是被格式化的值 => Hello abc!\n",
    "    println!(\"Hello {:.*}!\", 3, \"abcdefg\");\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## [进制](https://course.rs/basic/formatted-output.html#进制)\n",
    "\n",
    "可以使用 `#` 号来控制数字的进制输出：\n",
    "\n",
    "- `#b`, 二进制\n",
    "- `#o`, 八进制\n",
    "- `#x`, 小写十六进制\n",
    "- `#X`, 大写十六进制\n",
    "- `x`, 不带前缀的小写十六进制"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0b11011!\n",
      "0o33!\n",
      "27!\n",
      "0x1b!\n",
      "0x1B!\n",
      "1b!\n",
      "0b00011011!\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "{\n",
    "    // 二进制 => 0b11011!\n",
    "    println!(\"{:#b}!\", 27);\n",
    "    // 八进制 => 0o33!\n",
    "    println!(\"{:#o}!\", 27);\n",
    "    // 十进制 => 27!\n",
    "    println!(\"{}!\", 27);\n",
    "    // 小写十六进制 => 0x1b!\n",
    "    println!(\"{:#x}!\", 27);\n",
    "    // 大写十六进制 => 0x1B!\n",
    "    println!(\"{:#X}!\", 27);\n",
    "\n",
    "    // 不带前缀的十六进制 => 1b!\n",
    "    println!(\"{:x}!\", 27);\n",
    "\n",
    "    // 使用0填充二进制，宽度为10 => 0b00011011!\n",
    "    println!(\"{:#010b}!\", 27);\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## [指数](https://course.rs/basic/formatted-output.html#指数)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1e9\n",
      "1E9\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "{\n",
    "    println!(\"{:2e}\", 1000000000); // => 1e9\n",
    "    println!(\"{:2E}\", 1000000000); // => 1E9\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## [指针地址](https://course.rs/basic/formatted-output.html#指针地址)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0x62175d831630\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "let v= vec![1, 2, 3];\n",
    "println!(\"{:p}\", v.as_ptr()) // => 0x600002324050"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## [转义](https://course.rs/basic/formatted-output.html#转义)\n",
    "\n",
    "有时需要输出 `{`和`}`，但这两个字符是特殊字符，需要进行转义："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      " Hello \"{World}\" \n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "{\n",
    "    // \"{{\" 转义为 '{'   \"}}\" 转义为 '}'   \"\\\"\" 转义为 '\"'\n",
    "    // => Hello \"{World}\" \n",
    "    println!(\" Hello \\\"{{World}}\\\" \");\n",
    "\n",
    "    // 下面代码会报错，因为占位符{}只有一个右括号}，左括号被转义成字符串的内容\n",
    "    // println!(\" {{ Hello } \");\n",
    "    // 也不可使用 '\\' 来转义 \"{}\"\n",
    "    // println!(\" \\{ Hello \\} \")\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 在格式化字符串时捕获环境中的值"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Hello, sunface!\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "fn get_person() -> String {\n",
    "    String::from(\"sunface\")\n",
    "}\n",
    "\n",
    "{\n",
    "    let person = get_person(); // 输出一个函数的返回值\n",
    "    println!(\"Hello, {person}!\");\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n",
      "thread '<unnamed>' panicked at src/lib.rs:149:5:\n",
      "Hello, sunface!\n",
      "stack backtrace:\n",
      "   0: __rustc::rust_begin_unwind\n",
      "             at /rustc/1159e78c4747b02ef996e55082b704c09b970588/library/std/src/panicking.rs:697:5\n",
      "   1: core::panicking::panic_fmt\n",
      "             at /rustc/1159e78c4747b02ef996e55082b704c09b970588/library/core/src/panicking.rs:75:14\n",
      "   2: ctx::run_user_code_20::{{closure}}\n",
      "   3: core::ops::function::FnOnce::call_once\n",
      "   4: <core::panic::unwind_safe::AssertUnwindSafe<F> as core::ops::function::FnOnce<()>>::call_once\n",
      "   5: __rust_try.llvm.12863690636955465153\n",
      "   6: std::panic::catch_unwind\n",
      "   7: run_user_code_20\n",
      "   8: evcxr::runtime::Runtime::run_loop\n",
      "   9: evcxr::runtime::runtime_hook\n",
      "  10: evcxr_jupyter::main\n",
      "note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.\n"
     ]
    }
   ],
   "source": [
    "fn get_person() -> String {\n",
    "    String::from(\"sunface\")\n",
    "}\n",
    "\n",
    "{\n",
    "    let person = get_person();\n",
    "    panic!(\"Hello, {person}!\");\n",
    "}"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Rust",
   "language": "rust",
   "name": "rust"
  },
  "language_info": {
   "codemirror_mode": "rust",
   "file_extension": ".rs",
   "mimetype": "text/rust",
   "name": "Rust",
   "pygment_lexer": "rust",
   "version": ""
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
